grammar CommandLineGrammar;

// java -jar antlr-4.2-complete.jar Grammar.g4 -o generated

options {
  language = Java;
}

@header {
  package gatperdut.chato.core.interpreter.grammar.generated;
  
  import gatperdut.chato.core.interpreter.grammar.comminfo.CommandInfo;
  import gatperdut.chato.core.interpreter.grammar.comminfo.CommandInfo.CommandType;
  import gatperdut.chato.core.interpreter.grammar.comminfo.indexedword.IndexedWord;
  import gatperdut.chato.core.interpreter.grammar.comminfo.indexedword.IndexedWord.RefType;
  import gatperdut.chato.core.interpreter.grammar.comminfo.ManipulationInfo.ManipulationType;
  import gatperdut.chato.core.interpreter.grammar.comminfo.FoodInfo.ConsumptionType;
  import gatperdut.chato.core.interpreter.grammar.comminfo.SetsInfo.SetsOperation;
  
  import gatperdut.chato.core.interpreter.grammar.comminfo.CommunicationInfo;
  import gatperdut.chato.core.interpreter.grammar.comminfo.LookInfo;
  import gatperdut.chato.core.interpreter.grammar.comminfo.ThrowInfo;
  import gatperdut.chato.core.interpreter.grammar.comminfo.GoInfo;
  import gatperdut.chato.core.interpreter.grammar.comminfo.ItemTransferInfo;
  import gatperdut.chato.core.interpreter.grammar.comminfo.LookInfo;
  import gatperdut.chato.core.interpreter.grammar.comminfo.EmoteInfo;
  import gatperdut.chato.core.interpreter.grammar.comminfo.SpeakInfo;
  import gatperdut.chato.core.interpreter.grammar.comminfo.ManipulationDoorInfo;
  import gatperdut.chato.core.interpreter.grammar.comminfo.ManipulationContainerInfo;
  import gatperdut.chato.core.interpreter.grammar.comminfo.SpillInfo;
  import gatperdut.chato.core.interpreter.grammar.comminfo.FillInfo;
  import gatperdut.chato.core.interpreter.grammar.comminfo.EmptyInfo;
  import gatperdut.chato.core.interpreter.grammar.comminfo.WearInfo;
  import gatperdut.chato.core.interpreter.grammar.comminfo.RemoveInfo;
  import gatperdut.chato.core.interpreter.grammar.comminfo.StatusInfo;
  import gatperdut.chato.core.interpreter.grammar.comminfo.SkillsInfo;
  import gatperdut.chato.core.interpreter.grammar.comminfo.ListItemTemplatesInfo;
  import gatperdut.chato.core.interpreter.grammar.comminfo.FoodInfo;
  import gatperdut.chato.core.interpreter.grammar.comminfo.InvInfo;
  import gatperdut.chato.core.interpreter.grammar.comminfo.HelpInfo;
  import gatperdut.chato.core.interpreter.grammar.comminfo.CraftInfo;
  import gatperdut.chato.core.interpreter.grammar.comminfo.SetsInfo;
  import gatperdut.chato.core.interpreter.grammar.comminfo.SetInfo;
  import gatperdut.chato.core.interpreter.grammar.comminfo.SetInfo.SetType;
  import gatperdut.chato.core.interpreter.grammar.comminfo.SwitchInfo;
  import gatperdut.chato.core.interpreter.grammar.comminfo.QuitInfo;
  import gatperdut.chato.core.interpreter.grammar.comminfo.DocumentInfo;
  import gatperdut.chato.core.interpreter.grammar.comminfo.ScoreInfo;
  import gatperdut.chato.core.interpreter.grammar.comminfo.HitInfo;
  import gatperdut.chato.core.interpreter.grammar.comminfo.FleeInfo;
  import gatperdut.chato.core.interpreter.grammar.comminfo.StopInfo;
  import gatperdut.chato.core.interpreter.grammar.comminfo.JunkInfo;
  import gatperdut.chato.core.interpreter.grammar.comminfo.ExitsInfo;
  import gatperdut.chato.core.interpreter.grammar.comminfo.ShutdownInfo;
  import gatperdut.chato.core.interpreter.grammar.comminfo.COIRInfo;
  import gatperdut.chato.core.interpreter.grammar.comminfo.MudStatsInfo;

  import gatperdut.chato.constants.CSConstantsMovement.Direction;
  
} 

@members {
  	
  private CommandInfo ci;
	
  private boolean stringEmptyAndNotNull(String s) {
    return s != null && !s.matches("[' ' | '\t']+") && !s.equals("");
  }

}

command returns [CommandInfo commandInfo]
@after {
	 { $commandInfo = ci; }
}
	: 
	| say
	| tell
	| shout
	| direction
	| get
	| craft
	| put
	| drop
	| give
	| look
	| eat
	| drink
	| hurl
	| emote
	| speak
	| exits
	| inventory
	| open
	| close
	| lock
	| unlock
	| spill
	| fill
	| empty
	| wear
	| remove
	| status
	| skills
	| set
	| switchHands
	| sets
	| document
	| hit
	| flee
	| stop
	| junk
	| score
	| quit
	| help
	| adminActions
	;

direction
@init {
	ci = new GoInfo();
}
	: WS?
	(GO_NORTH
	{
		((GoInfo) ci).setDirection( Direction.NORTH );
		
	}
	| GO_SOUTH
	{
		((GoInfo) ci).setDirection( Direction.SOUTH );
	}
	| GO_WEST
	{
		((GoInfo) ci).setDirection( Direction.WEST );
	}
	| GO_EAST
	{
		((GoInfo) ci).setDirection( Direction.EAST );
	}
	| GO_UP
	{
		((GoInfo) ci).setDirection( Direction.UP );
	}
	| GO_DOWN
	{
		((GoInfo) ci).setDirection( Direction.DOWN );
	}
	)
	WS? oe=bracketedEmote? WS?
	{
		if ( $oe.text != null ) {
			ci.setEmote( $oe.s );
		}
	}
	;

tell
@init {
	ci = new CommunicationInfo( CommandType.TELL );
	StringBuilder sb = new StringBuilder("");
}
	: WS? TELL WS whom=indexedWord oe=communicationEmote s=speech WS?
	{
		((CommunicationInfo) ci).setWhom( $whom.iw );
		sb.append($oe.s); // this appends only WS
		
		if ( stringEmptyAndNotNull( $s.text ) ) {
			sb.append( $s.text );
		};
		((CommunicationInfo) ci).setSpeech( sb.toString() );
	}
	;

say
@init {
	ci = new CommunicationInfo( CommandType.SAY );
	StringBuilder sb = new StringBuilder("");
}
	: WS? SAY oe=communicationEmote s=speech WS?
	{
		sb.append( $oe.s ); // this appends only WS
		if ( stringEmptyAndNotNull( $s.text ) ) {
			sb.append( $s.text );
		}
		((CommunicationInfo) ci).setSpeech( sb.toString() );
	}
	;

shout
@init {
	ci = new CommunicationInfo( CommandType.SHOUT );
	StringBuilder sb = new StringBuilder("");
}
	: WS? SHOUT oe=communicationEmote s=speech WS?
	{
		sb.append( $oe.s ); // this appends only WS
		if ( stringEmptyAndNotNull( $s.text ) ) {
			sb.append( $s.text );
		}
		((CommunicationInfo) ci).setSpeech( sb.toString() );
	}
	;

get
	: getRoom
	| getContainer 
	;

getRoom
@init {
	ci = new ItemTransferInfo( CommandType.GET_ROOM );
}
	: WS? GET WS what=indexedWord (WS? be=bracketedEmote)? WS?
	{
		((ItemTransferInfo) ci).setWhat( $what.iw );
		if ($be.text != null) {
			ci.setEmote( $be.s );
		}
	}
	;

getContainer
@init {
	ci = new ItemTransferInfo( CommandType.GET_CONTAINER );
}
	: WS? GET WS what=indexedWord WS from=indexedWord (WS? dot=DOT)? (WS? be=bracketedEmote)? WS?
	{
		((ItemTransferInfo)ci).setWhat( $what.iw );
		((ItemTransferInfo)ci).setFrom( $from.iw );
		((ItemTransferInfo)ci).setGround( $dot.text != null );
		if ( $be.text != null ) {
			ci.setEmote( $be.s );
		}
	}
	;

put
@init {
	ci = new ItemTransferInfo( CommandType.PUT );
}
	: WS? PUT WS what=indexedWord WS in=indexedWord WS? (dot=DOT WS?)? be=bracketedEmote? WS?
	{
		((ItemTransferInfo)ci).setWhat( $what.iw );
		((ItemTransferInfo)ci).setIn( $in.iw );
		((ItemTransferInfo)ci).setGround( $dot.text != null );
		if ( $be.text != null ) {
			ci.setEmote( $be.s );
		}
	}
	;

drop
@init {
	ci = new ItemTransferInfo( CommandType.DROP );
}
	: WS? DROP WS what=indexedWord (WS? be=bracketedEmote)? WS?
	{
		((ItemTransferInfo)ci).setWhat( $what.iw );
		if ( $be.text != null ) {
			ci.setEmote( $be.s );
		}
	}
	;

give
@init {
	ci = new ItemTransferInfo( CommandType.GIVE );
}
	: WS? GIVE WS what=indexedWord WS whom=indexedWord (WS? be=bracketedEmote)? WS?
	{
		((ItemTransferInfo) ci).setWhat( $what.iw );
		((ItemTransferInfo) ci).setWhom( $whom.iw );
		if ( $be.text != null ) {
			ci.setEmote( $be.s );
		}
	}
	;

look
	: WS? LOOK WS?
	{
		ci = new LookInfo( CommandType.LOOK );
	}
	| lookAt
	| lookIn
	| lookWorn
	;
	
eat
@init {
	ci = new FoodInfo( ConsumptionType.EAT );
}
	: WS? EAT WS iw=indexedWord (WS i=integer)? (WS? d=DOT)? (WS? be=bracketedEmote)? WS?
	{
		((FoodInfo) ci).setWhat( $iw.iw );
		if ($d.text != null) {
			((FoodInfo) ci).setGround( true );
		}
		if ( $i.text != null ) {
			((FoodInfo) ci).setAmount( $i.s );
		}
		if ( $be.text != null ) {
			ci.setEmote( $be.s );
		}
	}
	;

drink
@init {
	ci = new FoodInfo( ConsumptionType.DRINK );
}
	: WS? DRINK WS iw=indexedWord (WS i=integer)? (WS? d=DOT)? (WS? be=bracketedEmote)? WS?
	{
		((FoodInfo) ci).setWhat( $iw.iw );
		if ( $d.text != null ) {
			((FoodInfo) ci).setGround( true );
		}
		if ( $i.text != null ) {
			((FoodInfo) ci).setAmount( $i.s );
		}
		if ( $be.text != null ) {
			ci.setEmote( $be.s );
		}
	}
	;

lookAt // look (obj/poss (.))/who
@init{
	ci = new LookInfo( CommandType.LOOK_AT );
}
	: WS? LOOK WS iw=indexedWord (WS? dot=DOT)? WS?
		{
			((LookInfo) ci).setWhat( $iw.iw );
			((LookInfo) ci).setGround( $dot.text != null );
		}
	;

lookIn
@init{
	ci = new LookInfo( CommandType.LOOK_IN );
}
	: WS? LOOK WS? DOT WS? iw=indexedWord (WS? dot=DOT)? WS?
		{
			((LookInfo) ci).setWhat( $iw.iw );
			((LookInfo) ci).setGround( $dot.text != null );
		}
	;

lookWorn
@init {
	ci = new LookInfo( CommandType.LOOK_WORN );
}
	: WS? LOOK WS iw1=indexedWord WS iw2=indexedWord WS?
		{
			((LookInfo) ci).setWhat( $iw1.iw );
			((LookInfo) ci).setWho( $iw2.iw );
		}
	;

fill
@init {
	ci = new FillInfo();
}
	: WS? FILL WS iw1=indexedWord WS iw2=indexedWord (WS ground=DOT)? (WS? be=bracketedEmote)? WS?
	{
		((FillInfo) ci).setToBeFilled( $iw1.iw );
		((FillInfo) ci).setToFillFrom( $iw2.iw );
		if ( $ground.text != null ) {
			((FillInfo) ci).setGround (true);
		}
		if ( $be.text != null ) {
			ci.setEmote( $be.s );
		}
	}
	;

spill
@init {
	ci = new SpillInfo();
}
	: WS? SPILL WS iw1=indexedWord (WS i=integer)? (WS iw2=indexedWord (WS? dot=DOT)? )?  (WS? be=bracketedEmote)? WS?
		{
			((SpillInfo) ci).setToBeSpilled( $iw1.iw );
			if ( $iw2.text != null ) {
				((SpillInfo) ci).setSpillInto( $iw2.iw );
			}
			if ( $i.text != null ) {
				((SpillInfo) ci).setAmount( $i.s );
			}
			if ($dot.text != null) {
				((SpillInfo) ci).setGround( true );
			}
			if ( $be.text != null ) {
				ci.setEmote( $be.s );
			}
		}
	;

empty
@init {
	ci = new EmptyInfo();
}
	: WS? EMPTY WS iw1=indexedWord (WS? be=bracketedEmote)? WS?
	{
		((EmptyInfo) ci).setEmptyFrom( $iw1.iw );
		if ( $be.text != null ) {
			ci.setEmote( $be.s );
		}
	}
	;

switchHands
@init {
	ci = new SwitchInfo();
}
	: WS? SWITCH (WS? be=bracketedEmote)? WS?
	{
		if ( $be.text != null ) {
			ci.setEmote( $be.s );
		}
	}
	;

hurl
@init {
	ci = new ThrowInfo();
}
	: WS? THROW WS iw=indexedWord WS td=aimedDirection (WS? be=bracketedEmote)? WS?
	{
		((ThrowInfo) ci).setWhat( $iw.iw );
		((ThrowInfo) ci).setDirection( $td.d );
		if ( $be.text != null ) {
			ci.setEmote( $be.s );
		}
	}
	;

craft
@init {
	ci = new CraftInfo();	
}
	: WS? CRAFT WS? s=speech WS?
	{
		((CraftInfo) ci).setCommand( $s.text );
	}
	;

emote
@init {
	ci = new EmoteInfo();
}
	: WS? be=bracketedEmote WS?
	{
		if ( $be.text != null ) {
			ci.setEmote( $be.s );
		}
	}
	;

speak
@init {
	ci = new SpeakInfo();
}
	: WS? SPEAK (WS w=speech)? WS?
	{
		((SpeakInfo) ci).setLanguage( $w.text );
	}
	;

exits
@init {
	ci = new ExitsInfo();
}
	: WS? EXITS WS?
	;

open
	: openDoor
	| openContainer
	;

openDoor
@init {
	ci = new ManipulationDoorInfo( ManipulationType.OPEN );
}
	: WS? OPEN WS ad=aimedDirection (WS? be=bracketedEmote)? WS?
	{
		((ManipulationDoorInfo) ci).setDirection( $ad.d );
		if ($be.text != null) {
			ci.setEmote( $be.s );
		}
	}
	;

openContainer
@init {
	ci = new ManipulationContainerInfo( ManipulationType.OPEN );
}
	: WS? OPEN WS iw=indexedWord (WS? dot=DOT)? (WS? be=bracketedEmote)? WS?
	{
		((ManipulationContainerInfo) ci).setWhat( $iw.iw );
		((ManipulationContainerInfo) ci).setGround( $dot.text != null );
		if ( $be.text != null ) {
			ci.setEmote( $be.s );
		}
	}
	;

close
	: closeDoor
	| closeContainer
	;

closeDoor
@init {
	ci = new ManipulationDoorInfo( ManipulationType.CLOSE );
}
	: WS? CLOSE WS ad=aimedDirection (WS? be=bracketedEmote)? WS?
	{
		((ManipulationDoorInfo) ci).setDirection( $ad.d );
		if ( $be.text != null ) {
			ci.setEmote( $be.s );
		}
	}
	;

closeContainer
@init {
	ci = new ManipulationContainerInfo( ManipulationType.CLOSE );
}
	: WS? CLOSE WS iw=indexedWord (WS? dot=DOT)? (WS? be=bracketedEmote)? WS?
	{
		((ManipulationContainerInfo) ci).setWhat( $iw.iw );
		((ManipulationContainerInfo) ci).setGround( $dot.text != null );
		if ( $be.text != null ) {
			ci.setEmote( $be.s );
		}
	}
	;

lock
	: lockDoor
	| lockContainer
	;
	
lockDoor
@init {
	ci = new ManipulationDoorInfo( ManipulationType.LOCK );
}
	: WS? LOCK WS ad=aimedDirection (WS? be=bracketedEmote)? WS?
	{
		((ManipulationDoorInfo) ci).setDirection( $ad.d );
		if ( $be.text != null ) {
			ci.setEmote( $be.s );
		}
	}
	;

lockContainer
@init {
	ci = new ManipulationContainerInfo( ManipulationType.LOCK );
}
	: WS? LOCK WS iw=indexedWord (WS? dot=DOT)? (WS? be=bracketedEmote)? WS?
	{
		((ManipulationContainerInfo) ci).setWhat( $iw.iw );
		((ManipulationContainerInfo) ci).setGround( $dot.text != null );
		if ( $be.text != null ) {
			ci.setEmote( $be.s );
		}
	}
	;

unlock
	: unlockDoor
	| unlockContainer
	;
	
unlockDoor
@init {
	ci = new ManipulationDoorInfo( ManipulationType.UNLOCK );
}
	: WS? UNLOCK WS ad=aimedDirection (WS? be=bracketedEmote)? WS?
	{
		((ManipulationDoorInfo) ci).setDirection( $ad.d );
		if ( $be.text != null ) {
			ci.setEmote( $be.s );
		}
	}
	;

unlockContainer
@init {
	ci = new ManipulationContainerInfo( ManipulationType.UNLOCK );
}
	: WS? UNLOCK WS iw=indexedWord (WS? dot=DOT)? (WS? be=bracketedEmote)? WS?
	{
		((ManipulationContainerInfo) ci).setWhat( $iw.iw );
		((ManipulationContainerInfo) ci).setGround( $dot.text != null );
		if ( $be.text != null ) {
			ci.setEmote( $be.s );
		}
	}
	;

sets
	: merge
	| split
	;
	
merge
@init {
	ci = new SetsInfo( SetsOperation.MERGE );
}
	: WS? MERGE WS iw1=indexedWord (WS? dot1=DOT WS? | WS) iw2=indexedWord (WS? dot2=DOT)? WS?
	{
		((SetsInfo) ci).setSet1( $iw1.iw );
		((SetsInfo) ci).setSet2( $iw2.iw );
		((SetsInfo) ci).setGround1( $dot1.text != null );
		((SetsInfo) ci).setGround2( $dot2.text != null );
	}
	;

split
@init {
	ci = new SetsInfo( SetsOperation.SPLIT );
}
	:	WS? SPLIT WS iw=indexedWord (WS? dot=DOT WS? | WS) n=integer WS?
	{
		((SetsInfo) ci).setSet1( $iw.iw );
		((SetsInfo) ci).setGround1( $dot.text != null );
		((SetsInfo) ci).setAmount( $n.s );
	}
	;

hit
@init {
	ci = new HitInfo();
}
	: WS? HIT WS iw=indexedWord WS?
	{
		((HitInfo) ci).setWhom( $iw.iw);
	}
	;

flee
@init {
	ci = new FleeInfo();
}
	: WS? FLEE ( WS
	(  GO_NORTH
	{
		((FleeInfo) ci).setDirection( Direction.NORTH );
	}
	| GO_EAST
	{
		((FleeInfo) ci).setDirection( Direction.EAST );
	}
	| GO_SOUTH
	{
		((FleeInfo) ci).setDirection( Direction.SOUTH );
	}
	| GO_WEST
	{
		((FleeInfo) ci).setDirection( Direction.WEST );
	}
	| GO_UP
	{
		((FleeInfo) ci).setDirection( Direction.UP );
	}
	| GO_DOWN
	{
		((FleeInfo) ci).setDirection( Direction.DOWN );
	}
	| OFF
	{
		((FleeInfo) ci).setStopFleeing( true );
	}
	) )? WS?
	;

stop
@init {
	ci = new StopInfo();
}
	: WS? STOP WS?
	;

wear
@init {
	ci = new WearInfo();
}
	: WS? WEAR WS iw=indexedWord (WS w=word)? (WS? be=bracketedEmote)? WS?
	{
		((WearInfo) ci).setWhat( $iw.iw );
		if ($w.text != null) {
			((WearInfo) ci).setWearLoc( $w.text );
		}
		if ( $be.text != null ) {
			ci.setEmote( $be.s );
		}
	}
	;

remove
@init {
	ci = new RemoveInfo();
}
	: WS? REMOVE WS iw=indexedWord (WS? be=bracketedEmote)? WS?
	{
		((RemoveInfo) ci).setWhat( $iw.iw );
		if ( $be.text != null ) {
			ci.setEmote( $be.s );
		}
	}
	;

status
@init {
	ci = new StatusInfo();
}
	: WS? STATUS WS?
	;

skills
@init {
	ci = new SkillsInfo();
}
	: WS? SKILLS WS?
	;

set
@init {
	ci = new SetInfo();
}
	: WS? SET WS
	( PACIFIST
	{
		((SetInfo) ci).setSetType( SetType.PACIFIST);
	}
	| ACCEPTGIVE
	{
		((SetInfo) ci).setSetType( SetType.ACCEPTGIVE);
	}
	)
	WS
	(ON
	{
		((SetInfo) ci).setOn( true );
	}
	| OFF
	{
		((SetInfo) ci).setOn( false );	
	}
	) WS?
	;

help
@init {
	ci = new HelpInfo();
}
	: WS? HELP WS s=speech WS?
	{
		((HelpInfo) ci).setHelpOn( $s.text );
	}
	;

inventory
@init {
	ci = new InvInfo();
}
	: WS? INVENTORY WS?
	;

document
@init {
	ci = new DocumentInfo();
}
	: WS? DOCUMENT WS i=integer WS?
	{
		((DocumentInfo) ci).setDocID( $i.s );
	}
	;

score
@init {
	ci = new ScoreInfo();
}
	: WS? SCORE WS?
	;
	
junk
@init {
	ci = new JunkInfo();
}
	: WS? JUNK WS iw=indexedWord WS?
	{
		((JunkInfo) ci).setWhat( $iw.iw );
	}
	;

quit
@init {
	ci = new QuitInfo();
}
	: WS? QUIT WS?
	;


adminActions
	: ADMIN a_shutdown
	| ADMIN a_coir //create object in room
	| ADMIN a_mudStats
	| ADMIN a_lit
	;

a_lit
@init {
	ci = new ListItemTemplatesInfo();
}
	: WS? A_LISTITEMTEMPLATES (WS w=word
	{
		((ListItemTemplatesInfo) ci).getKeywords().add( $w.text );	
	}
	)* WS?
	;

a_mudStats
@init {
	ci = new MudStatsInfo();
}
	: WS? A_MUDSTATS (WS w=word
	{
		((MudStatsInfo) ci).getSpecifics().add( $w.text );	
	}
	)* WS?
	;

a_coir
@init {
	ci = new COIRInfo();
}
	: WS? A_COIR WS c=integer (WS n=integer)? WS?
	{
		((COIRInfo) ci).setCode( $c.s );
		if ( $n.text != null ) {
			((COIRInfo) ci).setAmount( $n.s );
		}
	}
	;

a_shutdown
@init {
	ci = new ShutdownInfo();
}
	: WS? A_SHUTDOWN WS?
	;

bracketedEmote returns [String s]
@init {
	StringBuilder sb = new StringBuilder("");
	int openPos;
	int accum = 0;
}
@after {
	$s = sb.toString();
}
	: OPEN_B
	  {
	  	openPos = $OPEN_B.getStartIndex();
	  }
	  (
		w=word
		{
			sb.append( $w.text );
		}
	  | i=integer
	  	{
			sb.append( $i.s );
		}
	  | mw=markedWord
	    {
	    	ci.getiWords().add( $mw.iw );
	   		// --substract to the marked word's start position the OPEN position -2 - accum
			$mw.iw.setPos( $mw.iw.getPos() - openPos - 2 - accum);
			accum += $mw.iw.getWord().length() + $mw.il;
	    }
	  | p=punctuation
	    {
			sb.append( $p.s );
		}
	  | DOT
	  	{
			sb.append( "." );
		}
	  | WS
	  	{
			sb.append( $WS.text );
		}
	  | STAR
	  	{
			sb.append( "*" );
		}
	  | TILDE
	  {
			sb.append( "~" );
	  }
	  | OPEN_B
	  {
			sb.append( "(" );
	  }
	  | CLOSE_B
	  {
			sb.append( ")" );
	  }
	  | AT
	  {
	  		sb.append( "@" );
	  }
	  )* CLOSE_B
	;

communicationEmote returns [String s]
@init {
	StringBuilder sb = new StringBuilder("");
}
@after {
	$s = sb.toString();
}
	: prebefore=WS? ( WS? b=bracketedEmote before=WS? )?
	{
		if ( $b.text != null ) { // there's an emote
			if ( $before.text != null && $before.text.length() > 1 ) {
				sb.append( $before.text.substring( 1, $before.text.length() ) );
			}
			ci.setEmote( $b.s );
		} else {
			if ( $prebefore.text != null && $prebefore.text.length() > 1 ) { // no BEmote: use the first set of spaces
				sb.append( $prebefore.text.substring( 1, $prebefore.text.length() ) );
			}
		}
	}
	;

speech
	: .*?
	;

markedWord returns [IndexedWord iw, int il] //il=index length (e.g. "34.")
	: o=oRefInd
		{
			$iw = $o.oIW;
			$il = $o.il;
		}
	| e=eRefInd
		{
			$iw = $e.eIW;
			$il = $e.il;
		}
	;

oRefInd returns [IndexedWord oIW, int il] //il=index length (e.g. "34.")
	: STAR iw=indexedWord
		{
			$oIW = $iw.iw;
			$oIW.setPos( $oIW.getPos() );
			$oIW.setRefType( RefType.OBJECT );
			$il = $iw.il + 1; // +1 -> star
		}
 	;

eRefInd returns [IndexedWord eIW, int il] //il=index length (e.g. "34.")
	: TILDE iw=indexedWord
		{
			$eIW = $iw.iw;
			$eIW.setPos( $eIW.getPos() );
			$eIW.setRefType( RefType.ENTITY );
			$il = $iw.il + 1; // +1 -> tilde
		}
 	;
 				
indexedWord returns [IndexedWord iw, int il] //il=index length (e.g. "34.")
	: i=integer DOT w=word
		{
			$iw = new IndexedWord( $i.s + "." + $w.text, $i.si );
			$il = Integer.toString( $i.s ).length() + 1;
		}
	| w=word
		{
			$iw = new IndexedWord( $w.text, $w.si );
			$il = 0;
		}
	;

word returns [int si]
	: WORD
		{
			$si = $WORD.getStartIndex();
		}
	;
punctuation returns [String s]
	: PUNCTUATION
		{
			$s = $PUNCTUATION.text;
		}
	;
	
integer returns [int s, int si]
	: INTEGER
		{
			$s = Integer.parseInt( $INTEGER.text );
			$si = $INTEGER.getStartIndex();
		}
	;

aimedDirection returns [Direction d] 
	: GO_NORTH
	{
		$d = Direction.NORTH;
	}
	| GO_EAST
	{
		$d = Direction.EAST;
	}
	| GO_SOUTH
	{
		$d = Direction.SOUTH;
	}
	| GO_WEST
	{
		$d = Direction.WEST;
	}
	| GO_UP
	{
		$d = Direction.UP;
	}
	| GO_DOWN
	{
		$d = Direction.DOWN;
	}
	;

SAY : 'say' | 'sa';
TELL:'tell' | 'tel' | 'te' | 't';
SHOUT:'shout' | 'shou' | 'sho' | 'sh';

GO_NORTH: 'north' | 'nort' | 'nor' | 'no' | 'n' ;
GO_EAST: 'east' | 'eas' | 'ea' | 'e' ;
GO_SOUTH: 'south' | 'sout' | 'sou' | 'so' | 's';
GO_WEST:'west' | 'wes' | 'we' | 'w';
GO_UP : 'up' | 'u';
GO_DOWN: 'down' | 'dow' | 'do' | 'd';

GET:'get' | 'ge' | 'g';
PUT:'put' | 'pu' |'p';
DROP:'drop' | 'dro' | 'dr';
GIVE: 'give' | 'giv' | 'gi' | 'g';

SPILL: 'spill' | 'spil' | 'spi';
FILL: 'fill' | 'fil' | 'fi' | 'f';
EMPTY: 'empty' | 'empt' | 'emp' | 'em';

EXITS: 'exits' | 'exit' | 'exi' | 'ex';

SPEAK: 'speak' | 'spea' | 'spe' | 'sp' ;

THROW: 'throw' | 'thro' | 'thr' | 'th' | 't';

EAT: 'eat' | 'ea';
DRINK: 'drink' | 'drin' | 'dri' | 'dr';

WEAR: 'wear' | 'wea';
REMOVE: 'remove' | 'remov' | 'remo' | 'rem' | 're' | 'r';

STATUS: 'status' | 'statu' | 'stat' | 'sta' | 'st';
SKILLS: 'skills' | 'skill' | 'skil' | 'ski' | 'sk';

SET: 'set' | 'se';
PACIFIST: 'pacifist' | 'pacifis' | 'pacifi' | 'pacif' | 'paci' | 'pac' | 'pa';
ACCEPTGIVE: 'acceptgive' | 'acceptgiv' | 'acceptgi' | 'acceptg';
ON: 'on';
OFF: 'off' | 'of';

LOOK: 'look' | 'loo' | 'lo' | 'l';

HIT: 'hit' | 'hi';
FLEE: 'flee' | 'fle' | 'fl';

STOP: 'stop' | 'sto';

OPEN: 'open' | 'ope' | 'op' | 'o';
CLOSE: 'close' | 'clos' | 'clo' | 'cl' | 'c';
LOCK: 'lock' | 'loc';
UNLOCK: 'unlock' | 'unloc' | 'unlo' | 'unl' | 'un';

SWITCH: 'switch' | 'switc' | 'swit' | 'swi' | 'sw';

INVENTORY: 'inventory' | 'inventor' | 'invento' | 'invent' | 'inven' | 'inve' | 'inv' | 'in' | 'i';

DOCUMENT: 'document' | 'documen' | 'docume' | 'docum' | 'docu' | 'doc';

HELP: 'help' | 'hel' | 'he' | 'h';

MERGE: 'merge' | 'merg' | 'mer' | 'me' | 'm';
SPLIT: 'split' | 'spli' | 'spl';

CRAFT: 'c:';

SCORE: 'score' | 'scor' | 'sco' | 'sc';

JUNK: 'junk' | 'jun' | 'ju' | 'j';

// create object in room
A_COIR : 'coir' ;

QUIT: 'quit' | 'qui' | 'qu' | 'q' ;

A_SHUTDOWN: 'sd' ;
A_LISTITEMTEMPLATES: 'lit';
A_MUDSTATS: 'ms' ;

ADMIN: 'a:';


TILDE : '~';
STAR : '*';
OPEN_B : '(';
CLOSE_B : ')';
DOT : '.';
AT : '@';

WORD : CHAR+;
INTEGER : DIGIT+;
PUNCTUATION: SYMBOL+;

fragment DIGIT : '0'..'9' ;
fragment CHAR : 'a'..'z' | 'A'..'Z';
fragment SYMBOL : ',' | '!' | '-' | '?' | '<' | '>' | ',' | '$' | '%' | ':' | '\'' | '_';

WS : (' ' | '\t')+;
